package com.vcredit.creditcat.redis;

import com.vcredit.framework.redis.RedisTokenException;
import com.vcredit.framework.redis.VcreditRedisSerializer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;

import java.util.Set;

/**
 * @description: ${todo} (描述这个文件的作用)
 * Project Name:credit_cat File Name:RedisServiceExt.java
 * Copyright (c) 2017/11/9 @author: 张新功 Inc.All Rights Reserved.
 */
public class RedisServiceExt {
  protected RedisTemplate<String, Object> redisTemplate;
  @Autowired
  private VcreditRedisSerializer redisSerializer;
  public RedisServiceExt() {
  }

  public RedisTemplate<String, Object> getRedisTemplate() {
    return this.redisTemplate;
  }

  public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
    this.redisTemplate = redisTemplate;
  }

  protected RedisSerializer getRedisSerializer() {
    return this.redisSerializer;
  }

  protected RedisSerializer getStringRedisSerializer() {
    return this.redisTemplate.getStringSerializer();
  }

  public boolean put(final String key, final Object val, final long time, final long token) throws RedisTokenException {
    return ((Boolean)this.redisTemplate.execute(new RedisCallback<Boolean>() {
      @Override
      public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
        if (RedisServiceExt.this.validToken(key, token)) {
          return RedisServiceExt.this.put(key, val, time);
        } else {
          throw new RedisTokenException("token validate exception");
        }
      }
    })).booleanValue();
  }

  public boolean put(final String key, final Object val, final long time) {
    return ((Boolean)this.redisTemplate.execute(new RedisCallback<Boolean>() {
      @Override
      public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
        byte[] keyb = RedisServiceExt.this.getStringRedisSerializer().serialize(key);
        byte[] valb = RedisServiceExt.this.getRedisSerializer().serialize(val);
        boolean flag = connection.setNX(keyb, valb).booleanValue();
        if (time > 0L && flag) {
          connection.expire(keyb, time);
        }

        return flag;
      }
    })).booleanValue();
  }

  public Object get(final String key, final long token) throws RedisTokenException {
    return this.redisTemplate.execute(new RedisCallback<Object>() {
      @Override
      public Object doInRedis(RedisConnection connection) throws DataAccessException {
        if (RedisServiceExt.this.validToken(key, token)) {
          return RedisServiceExt.this.get(key);
        } else {
          throw new RedisTokenException("token validate exception");
        }
      }
    });
  }

  public Object get(final String key) {
    return this.redisTemplate.execute(new RedisCallback<Object>() {
      @Override
      public Object doInRedis(RedisConnection connection) throws DataAccessException {
        byte[] keyb = RedisServiceExt.this.getStringRedisSerializer().serialize(key);
        byte[] valb = connection.get(keyb);
        return valb != null && valb.length > 0 ? RedisServiceExt.this.getRedisSerializer().deserialize(valb) : null;
      }
    });
  }

  public boolean del(final String key, final long token) throws RedisTokenException {
    return ((Boolean)this.redisTemplate.execute(new RedisCallback<Boolean>() {
      @Override
      public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
        if (RedisServiceExt.this.validToken(key, token)) {
          return RedisServiceExt.this.del(key);
        } else {
          throw new RedisTokenException("token validate exception");
        }
      }
    })).booleanValue();
  }

  public boolean del(final String key) {
    return ((Boolean)this.redisTemplate.execute(new RedisCallback<Boolean>() {
      @Override
      public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
        byte[] keyb = RedisServiceExt.this.getStringRedisSerializer().serialize(key);
        return connection.del(new byte[][]{keyb}).longValue() > 0L ? true : false;
      }
    })).booleanValue();
  }

  private boolean validToken(final String key, final long token) {
    return ((Boolean)this.redisTemplate.execute(new RedisCallback<Boolean>() {
      @Override
      public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
        byte[] keyb = RedisServiceExt.this.getRedisSerializer().serialize(RedisServiceExt.this.getLockName(key));
        byte[] valb = connection.get(keyb);
        if (valb != null && valb.length != 0) {
          System.out.println(token + "---" + (Long)RedisServiceExt.this.getRedisSerializer().deserialize(valb));
          return ((Long)RedisServiceExt.this.getRedisSerializer().deserialize(valb)).equals(token);
        } else {
          return false;
        }
      }
    })).booleanValue();
  }

  public boolean unToken(String key, long token) throws RedisTokenException {
    if (this.validToken(key, token)) {
      return this.del(this.getLockName(key));
    } else {
      throw new RedisTokenException("token validate exception");
    }
  }

  public Set<String> keys(String pattern) throws RedisTokenException {
    return redisTemplate.keys(pattern + "*");
  }

  public long getToken(String key) {
    while(true) {
      Long rediToken = null;
      Object obj = this.get(this.getLockName(key));
      if (obj == null) {
        rediToken = System.currentTimeMillis();
        if (this.put(this.getLockName(key), rediToken, 60L)) {
          return rediToken.longValue();
        }
      } else {
        try {
          new Thread();
          Thread.sleep(1000L);
        } catch (InterruptedException var5) {
          var5.printStackTrace();
        }
      }
    }
  }

  private String getLockName(String key) {
    return key + ".lock";
  }
}
